#include "tcpmgr.h"
#include <QJsonDocument>
#include <QJsonObject>
#include "usermgr.h"

TcpMgr::~TcpMgr()
{

}

TcpMgr::TcpMgr()
    : _host(""), _port(0), _b_recv_pending(false), _message_id(0), _message_len(0)
{
    // 连接 _socket连接建立信号和连接建立信号
    QObject::connect(&_socket, &QTcpSocket::connected, this, [this](){
        qDebug() << "Connected to Server success!";
        emit sig_con_success(true);
    });

    // 连接 缓冲区可读信号并处理
    QObject::connect(&_socket, &QTcpSocket::readyRead, [&]() {
        // 当有数据可读时，读取所有数据
        // 读取所有数据并追加到缓冲区
        _buffer.append(_socket.readAll());

        QDataStream stream(&_buffer, QIODevice::ReadOnly);
        stream.setVersion(QDataStream::Qt_5_0);

        forever {
            //先解析头部
           if(!_b_recv_pending){
               // 检查缓冲区中的数据是否足够解析出一个消息头（消息ID + 消息长度）
               if (_buffer.size() < static_cast<int>(sizeof(quint16) * 2)) {
                   return; // 数据不够，等待更多数据
               }
               // 预读取消息ID和消息长度，但不从缓冲区中移除
               stream >> _message_id >> _message_len;
               //将buffer 中的前四个字节移除
               _buffer = _buffer.mid(sizeof(quint16) * 2);
               // 输出读取的数据
               qDebug() << "Message ID:" << _message_id << ", Length:" << _message_len;
           }
            //buffer剩余长读是否满足消息体长度，不满足则退出继续等待接受
           if(_buffer.size() < _message_len){
                _b_recv_pending = true;
                return;
           }
           _b_recv_pending = false;
           // 读取消息体
           QByteArray messageBody = _buffer.mid(0, _message_len);
           qDebug() << "receive body msg is " << messageBody ;

           _buffer = _buffer.mid(_message_len);
           handleMsg(ReqId(_message_id),_message_len, messageBody);
        }});

    // 连接 连接断开事件并处理
    QObject::connect(&_socket, static_cast<void (QTcpSocket::*)(QTcpSocket::SocketError)>(&QTcpSocket::error),
                       [&](QTcpSocket::SocketError socketError) {
          qDebug() << "Error:" << _socket.errorString() ;
          switch (socketError) {
              case QTcpSocket::ConnectionRefusedError:
                  qDebug() << "Connection Refused!";
                  emit sig_con_success(false);
                  break;
              case QTcpSocket::RemoteHostClosedError:
                  qDebug() << "Remote Host Closed Connection!";
                  break;
              case QTcpSocket::HostNotFoundError:
                  qDebug() << "Host Not Found!";
                  emit sig_con_success(false);
                  break;
              case QTcpSocket::SocketTimeoutError:
                  qDebug() << "Connection Timeout!";
                  emit sig_con_success(false);
                  break;
              case QTcpSocket::NetworkError:
                  qDebug() << "Network Error!";
                  break;
              default:
                  qDebug() << "Other Error!";
                  break;
          }
    });

    // 连接 发送数据的信号和槽函数
    QObject::connect(this, &TcpMgr::sig_send_data, this, &TcpMgr::slot_send_data);

    initHandlers();
}

void TcpMgr::initHandlers()
{
    // 处理登录回包
    _handlers.insert(ID_CHAT_LOGIN_RSP, [this](ReqId reqid, int len, QByteArray data){
        qDebug() << "handle id is " << reqid << " data is " << data << " len is " << len;

        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonObject";
        }

        QJsonObject jsonObj = jsonDoc.object();
        int err = jsonObj["error"].toInt();

        if (!jsonObj.contains("error")) {
            qDebug() << "Login Failed, err is Json Parse err" << err;
            emit sig_login_failed(err);
            return;
        }

        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "Login Failed, err is " << err;
            emit sig_login_failed(err);
            return;
        }

        auto uid = jsonObj["uid"].toInt();
        auto name = jsonObj["name"].toString();
        auto nick = jsonObj["nick"].toString();
        auto icon = jsonObj["icon"].toString();
        auto sex = jsonObj["sex"].toInt();
        auto user_info = std::make_shared<UserInfo>(uid, name, nick, icon, sex);

        UserMgr::GetInstance()->SetUserInfo(user_info);
        UserMgr::GetInstance()->SetToken(jsonObj["token"].toString());

        if(jsonObj.contains("apply_list")){
            UserMgr::GetInstance()->AppendApplyList(jsonObj["apply_list"].toArray());
        }
        if(jsonObj.contains("friend_list")){
            UserMgr::GetInstance()->AppendFriendList(jsonObj["friend_list"].toArray());
        }

        emit sig_switch_chatdlg();
    });

    // 处理搜索用户回包
    _handlers.insert(ID_SEARCH_USER_RSP, [this](ReqId reqid, int len, QByteArray data){
        qDebug() << "handle id is " << reqid << " data is " << data << " len is " << len;

        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonObject";
        }

        QJsonObject jsonObj = jsonDoc.object();
        int err = jsonObj["error"].toInt();

        if (!jsonObj.contains("error")) {
            qDebug() << "Add Friend Failed, err is Json Parse err" << err;
            emit sig_user_search(nullptr);
            return;
        }

        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "Add Friend Failed, err is " << err;
            emit sig_user_search(nullptr);
            return;
        }

        auto search_info = std::make_shared<SearchInfo> (jsonObj["uid"].toInt(),
                jsonObj["name"].toString(), jsonObj["nick"].toString(),
                jsonObj["desc"].toString(), jsonObj["icon"].toString(), jsonObj["sex"].toInt());

        emit sig_user_search(search_info);
    });


    // 处理添加好友回包
    _handlers.insert(ID_ADD_FRIEND_RSP, [this](ReqId reqid, int len, QByteArray data){
        qDebug() << "handle id is " << reqid << " data is " << data << " len is " << len;

        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonObject";
        }

        QJsonObject jsonObj = jsonDoc.object();
        int err = jsonObj["error"].toInt();

        if (!jsonObj.contains("error")) {
            qDebug() << "Add Friend Failed, err is Json Parse err" << err;
            return;
        }

        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "Add Friend Failed, err is " << err;
            return;
        }

        qDebug() << "Add Friend REQ Success";
    });


    _handlers.insert(ID_NOTIFY_ADD_FRIEND_REQ, [this](ReqId reqid, int len, QByteArray data){
        qDebug() << "handle id is " << reqid << " data is " << data << " len is " << len;

        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonObject";
        }

        QJsonObject jsonObj = jsonDoc.object();
        int err = jsonObj["error"].toInt();

        if (!jsonObj.contains("error")) {
            qDebug() << "ID_NOTIFY_ADD_FRIEND_REQ Failed, err is Json Parse err" << err;
            return;
        }

        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "ID_NOTIFY_ADD_FRIEND_REQ Failed, err is " << err;
            return;
        }

        int from_uid = jsonObj["applyuid"].toInt();
        QString name = jsonObj["name"].toString();
        QString desc = jsonObj["desc"].toString();
        QString icon = jsonObj["icon"].toString();
        QString nick = jsonObj["nick"].toString();
        int sex = jsonObj["sex"].toInt();

        auto apply_info = std::make_shared<AddFriendApply>(from_uid, name, desc,icon, nick, sex);
        emit sig_friend_apply(apply_info);

        qDebug() << "ID_NOTIFY_ADD_FRIEND_REQ REQ Success";
    });

    _handlers.insert(ID_NOTIFY_AUTH_FRIEND_REQ, [this](ReqId reqid, int len, QByteArray data){
        qDebug() << "handle id is " << reqid << " data is " << data << " len is " << len;

        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonObject";
        }

        QJsonObject jsonObj = jsonDoc.object();
        int err = jsonObj["error"].toInt();

        if (!jsonObj.contains("error")) {
            qDebug() << "ID_NOTIFY_ADD_AUTH_REQ Failed, err is Json Parse err" << err;
            return;
        }

        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "ID_NOTIFY_ADD_AUTH_REQ Failed, err is " << err;
            return;
        }

        int from_uid = jsonObj["fromuid"].toInt();
        QString name = jsonObj["name"].toString();
        QString nick = jsonObj["nick"].toString();
        QString icon = jsonObj["icon"].toString();
        int sex = jsonObj["sex"].toInt();

        auto auth_info = std::make_shared<AuthInfo>(from_uid,name,
                                                    nick, icon, sex);

        emit sig_add_auth_friend(auth_info);
    });

    _handlers.insert(ID_ADD_FRIEND_RSP, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        qDebug() << "handle id is " << id << " data is " << data;
        // 将QByteArray转换为QJsonDocument
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

        // 检查转换是否成功
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonDocument.";
            return;
        }

        QJsonObject jsonObj = jsonDoc.object();

        if (!jsonObj.contains("error")) {
            int err = ErrorCodes::ERR_JSON;
            qDebug() << "Add Friend Failed, err is Json Parse Err" << err;
            return;
        }

        int err = jsonObj["error"].toInt();
        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "Add Friend Failed, err is " << err;
            return;
        }

         qDebug() << "Add Friend Success " ;
      });


    _handlers.insert(ID_AUTH_FRIEND_RSP, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        qDebug() << "handle id is " << id << " data is " << data;
        // 将QByteArray转换为QJsonDocument
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

        // 检查转换是否成功
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonDocument.";
            return;
        }

        QJsonObject jsonObj = jsonDoc.object();

        if (!jsonObj.contains("error")) {
            int err = ErrorCodes::ERR_JSON;
            qDebug() << "Auth Friend Failed, err is Json Parse Err" << err;
            return;
        }

        int err = jsonObj["error"].toInt();
        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "Auth Friend Failed, err is " << err;
            return;
        }

        auto name = jsonObj["name"].toString();
        auto nick = jsonObj["nick"].toString();
        auto icon = jsonObj["icon"].toString();
        auto sex = jsonObj["sex"].toInt();
        auto uid = jsonObj["uid"].toInt();
        auto rsp = std::make_shared<AuthRsp>(uid, name, nick, icon, sex);
        emit sig_auth_rsp(rsp);

        qDebug() << "Auth Friend Success " ;
      });

    _handlers.insert(ID_TEXT_CHAT_MSG_RSP, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        qDebug() << "handle id is " << id << " data is " << data;
        // 将QByteArray转换为QJsonDocument
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

        // 检查转换是否成功
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonDocument.";
            return;
        }

        QJsonObject jsonObj = jsonDoc.object();

        if (!jsonObj.contains("error")) {
            int err = ErrorCodes::ERR_JSON;
            qDebug() << "Chat Msg Rsp Failed, err is Json Parse Err" << err;
            return;
        }

        int err = jsonObj["error"].toInt();
        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "Chat Msg Rsp Failed, err is " << err;
            return;
        }

        qDebug() << "Receive Text Chat Rsp Success " ;
        //TODO: ui设置送达等标记 todo...
      });

    _handlers.insert(ID_NOTIFY_TEXT_CHAT_MSG_REQ, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        qDebug() << "handle id is " << id << " data is " << data;
        // 将QByteArray转换为QJsonDocument
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

        // 检查转换是否成功
        if (jsonDoc.isNull()) {
            qDebug() << "Failed to create QJsonDocument.";
            return;
        }

        QJsonObject jsonObj = jsonDoc.object();

        if (!jsonObj.contains("error")) {
            int err = ErrorCodes::ERR_JSON;
            qDebug() << "Notify Chat Msg Failed, err is Json Parse Err" << err;
            return;
        }

        int err = jsonObj["error"].toInt();
        if (err != ErrorCodes::SUCCESS) {
            qDebug() << "Notify Chat Msg Failed, err is " << err;
            return;
        }

        qDebug() << "Receive Text Chat Notify Success " ;
        auto msg_ptr = std::make_shared<TextChatMsg>(jsonObj["fromuid"].toInt(),
                jsonObj["touid"].toInt(),jsonObj["text_array"].toArray());
        emit sig_text_chat_msg(msg_ptr);
      });
}

void TcpMgr::handleMsg(ReqId reqid, int len, QByteArray data)
{
    auto find_iter = _handlers.find(reqid);
    if (find_iter == _handlers.end()) {
        qDebug() << "not found reqid [" << reqid << "] to handle";
        return;
    }
    find_iter.value()(reqid, len, data);
}

void TcpMgr::slot_tcp_connect(ServerInfo si)
{
    qDebug() << "receive tcp connect signal";
    qDebug() << "Connecting to server...";
    _host = si.Host;
    _port = static_cast<uint16_t>(si.Port.toUInt());
    _socket.connectToHost(_host, _port);
}

void TcpMgr::slot_send_data(ReqId reqId, QByteArray dataBytes)
{
    // 因为客户端发送数据可能在任何线程，为了保证线程安全，我们在要发送数据时发送TcpMgr的sig_send_data信号，然后实现接受这个信号的槽函数

    // 准备发送报文的Id和长度
    uint16_t id = reqId;
    quint16 len = static_cast<quint16>(dataBytes.size());

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setByteOrder(QDataStream::BigEndian);

    out << id << len;
    block.append(dataBytes);
    _socket.write(block);

    qDebug() << "send tcp msg: Message ID: " << id << " length: " << len << " body: " << dataBytes;
}
